Background

This folder contains analyses for showing the initial staining patterns we observed when applying FungaLight to oxidative stress damaged C. glabrata cells. Note that these are not exactly our first trial results, which suffer a lot more inconsistencies and abnormalities, due to our inexperience with the reagent and protocol in general. Rather, these are the “alpha” tests of the protocol after some preliminary tests, and represent at least “sensible” results, although with important caveats that we addressed in the later protocol optimization steps.

require(tidyverse)
Loading required package: tidyverse
── Attaching core tidyverse packages ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.2     ✔ readr     2.1.4
✔ forcats   1.0.0     ✔ stringr   1.5.0
✔ ggplot2   3.4.2     ✔ tibble    3.2.1
✔ lubridate 1.9.2     ✔ tidyr     1.3.0
✔ purrr     1.0.1     
── Conflicts ────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the ]8;;http://conflicted.r-lib.org/conflicted package]8;; to force all conflicts to become errors
require(flowCore)
Loading required package: flowCore
require(flowClust)
Loading required package: flowClust

Attaching package: ‘flowClust’

The following object is masked from ‘package:graphics’:

    box

The following object is masked from ‘package:base’:

    Map
require(openCyto)
Loading required package: openCyto
Registered S3 method overwritten by 'data.table':
  method           from
  print.data.table     
require(ggcyto)
Loading required package: ggcyto
Loading required package: ncdfFlow
Loading required package: BH
Loading required package: flowWorkspace
As part of improvements to flowWorkspace, some behavior of
GatingSet objects has changed. For details, please read the section
titled "The cytoframe and cytoset classes" in the package vignette:

  vignette("flowWorkspace-Introduction", "flowWorkspace")
require(cowplot)
Loading required package: cowplot

Attaching package: ‘cowplot’

The following object is masked from ‘package:lubridate’:

    stamp
require(ggridges)
Loading required package: ggridges
```r
old <- theme_set(theme_minimal())

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->


# Import data

> FCS files are stored in RDSS/user/flow cytometry, FCS is read and write into an input tsv table. The tsv file is avaliable from the Input folder.


<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuIyB1c2UgcmVsYXRpdmUgcGF0aCB0byBtYWtlIGl0IGVhc2llciBmb3IgY29sbGFib3JhdGlvblxuZGF0YS5wYXRoID0gXCIvVm9sdW1lcy9yZHNzX2JoZTIvVXNlci9IYW54aS1UYW5nL2Zsb3dfY3l0b21ldHJ5LzIwMjMwOTI5IEZ1bmdhTGlnaHQtQ2dsYS1hbmFseXNpcy9cIlxuZGF0MCA8LSByZWFkLmZsb3dTZXQocGF0aCA9IGRhdGEucGF0aCwgdHJhbnNmb3JtYXRpb24gPSBGQUxTRSwgICMgdGhlIG9yaWdpbmFsIHZhbHVlcyBhcmUgYWxyZWFkeSBsaW5lYXJpemVkLiBcbiAgICAgICAgICAgICAgICAgICAgIGVtcHR5VmFsdWUgPSBGQUxTRSwgIGFsdGVyLm5hbWVzID0gVFJVRSwgICAjIGNoYW5nZSBwYXJhbWV0ZXIgbmFtZXMgdG8gUiBmb3JtYXRcbiAgICAgICAgICAgICAgICAgICAgIGNvbHVtbi5wYXR0ZXJuID0gXCIuSHxGU0N8U1NDXCIpICMgb25seSBsb2FkIHRoZSBoZWlnaHQgdmFyaWFibGVzIGZvciB0aGUgZmx1b3Jlc2NlbnQgcGFyYW1ldGVyc1xuYGBgIn0= -->

```r
# use relative path to make it easier for collaboration
data.path = "/Volumes/rdss_bhe2/User/Hanxi-Tang/flow_cytometry/20230929 FungaLight-Cgla-analysis/"
dat0 <- read.flowSet(path = data.path, transformation = FALSE,  # the original values are already linearized. 
                     emptyValue = FALSE,  alter.names = TRUE,   # change parameter names to R format
                     column.pattern = ".H|FSC|SSC") # only load the height variables for the fluorescent parameters

Simplify the sample names

#source("../../../00-Shared/01-script/20220326-simplify-names-subroutine.R")
oriNames <- sampleNames(dat0)
tmp <- str_split(oriNames, pattern = "_", simplify = TRUE)[,c(1, 5)]
colnames(tmp) <- c("Date", "Treatment")
sample <- data.frame(tmp) %>% 
  mutate(
    date = mdy(Date),
    replicate = ifelse(str_sub(Treatment, 1, 1) == "B", "B", "A"),
    treatment = sub("B ", "", Treatment) %>% sub(".fcs", "", .) %>% 
      gsub("1M", "1000", .) %>% gsub("Mock", "0", .),
    treatment = factor(treatment, levels = sort(as.numeric(unique(treatment))))
  ) %>% 
  select(-Date, - Treatment)
tr.levels <- levels(sample$treatment)
rownames(sample) <- oriNames
dat <- dat0 # make a copy
pData(dat) <- sample
print(pData(dat) %>% as_tibble())
write_tsv(pData(dat), file = "../input/20230929-sample-list.tsv")

Basic gating

Outlier

The following gaphing steps are used to gate singlets by FSC and SSC values. Only singlets are included in analysis.

outlier.gate <- rectangleGate(filterId = "-outlier", "FSC.H" = c(1.2e5, 1e6), "SSC.H" = c(1e2, 1e6))
ggcyto(dat[c(2,20)], aes(x = FSC.H, y = SSC.H), subset = "root") +
  geom_hex(bins = 64) + geom_gate(outlier.gate) + facet_wrap(~name, ncol = 2) + ggcyto_par_set(limits = "instrument")
Coordinate system already present. Adding new coordinate system, which will replace the existing one.

# ----
# uncomment the code below to check on all data
# ----
# ggcyto(dat, aes(x = FSC.H, y = SSC.H), subset = "root") +
#   geom_hex(bins = 64) + geom_gate(outlier.gate) + facet_wrap(~name, ncol = 9) + ggcyto_par_set(limits = "instrument") +
#   theme_minimal_grid()
# ----
# end
# ----

Add gate to GS

# shorten the names of the samples for plotting
shortNames <- with(pData(dat), 
                   paste(substr(date, 6, 10), replicate,
                         paste0(treatment, "mM"), sep = "_"))
names(shortNames) <- sampleNames(dat)
gs <- GatingSet(dat) # create a GatingSet
# rename the GatingSet
if(all(sampleNames(gs) == names(shortNames)))
  pData(gs)$name <- shortNames
# add the outlier gate
gs_pop_add(gs, outlier.gate, parent = "root")
[1] 2
# compute
recompute(gs)
done!

Gate for singlets

scPars <- ggcyto_par_set(limits = list(x = c(0,1e6), y = c(30,300)))
ex <- Subset(dat[[19]], outlier.gate)
polygon <- matrix(c(1e5, 1e5, 1e6, 1e6, 
                    60, 75, 135,60), ncol = 2)
colnames(polygon) <- c("FSC.H", "FSC.W")
singlet.gate <- polygonGate(filterId = "singlet", .gate = polygon)
ggcyto(ex, aes(x = FSC.H, y = FSC.W)) + geom_hex(bins = 128) + geom_gate(singlet.gate) + geom_stats() + scPars
Coordinate system already present. Adding new coordinate system, which will replace the existing one.

Add this gate to the gatingSet

gs_pop_add(gs, singlet.gate, parent = "-outlier", name = "singlet")
[1] 3
recompute(gs)
done!
scPars <- ggcyto_par_set(limits = list(x = c(0,1e6), y = c(30,200)))
test <- sample(1:length(gs), 8)
ggcyto(gs[test], aes(x = FSC.H, y = FSC.W), subset = "-outlier") +
  geom_hex(bins = 128) + geom_gate("singlet") + facet_wrap(~name, ncol = 4) + 
  scPars# + theme(strip.text = element_blank())
Coordinate system already present. Adding new coordinate system, which will replace the existing one.

Check number of events after gating

FSC and SSC vs treatment and dye

FSC

mult_format <- function() {
     function(x) format(x/10000,digits = 2) 
}
#for(date in unique(sample$date)){
  p <- ggcyto(gs, aes(x = FSC.H), subset = "singlet") + 
    geom_density_ridges(aes(y = factor(treatment, levels = tr.levels)), 
                            fill = "forestgreen", alpha = 0.8) + 
    scale_x_continuous(labels = mult_format(), name = "FSC.H x 10000") +
    facet_wrap(~date + replicate, 
               labeller = labeller(.multi_line = FALSE)) + 
    ylab("H2O2 concentration")
  print(p)
Picking joint bandwidth of 12800
Picking joint bandwidth of 13400
Picking joint bandwidth of 15100
Picking joint bandwidth of 13100
Picking joint bandwidth of 13700
Picking joint bandwidth of 14700

#}

there is a trend of decreasing FSC with stronger H2O2 treatment

SSC

  p <- ggcyto(gs, aes(x = SSC.H), subset = "singlet") + 
    geom_density_ridges(aes(y = factor(treatment, levels = tr.levels)), 
                            fill = "forestgreen", alpha = 0.8) + 
    scale_x_continuous(labels = mult_format(), name = "SSC.H x 10000") +
    facet_wrap(~date + replicate, 
               labeller = labeller(.multi_line = FALSE)) + 
    ylab("H2O2 concentration")
  print(p)
Picking joint bandwidth of 11500
Picking joint bandwidth of 11600
Picking joint bandwidth of 13000
Picking joint bandwidth of 11600
Picking joint bandwidth of 11800
Picking joint bandwidth of 12600

SSC (complexity of cell, roughly) decreases with increasing H2O2 concentration

BL1.H (green staining)

#for(date in c("011124", "011524", "011624")){
  p <- ggcyto(gs, aes(x = BL1.H), subset = "singlet") + 
    geom_density_ridges(aes(y = factor(treatment, levels = tr.levels)), 
                            fill = "forestgreen", alpha = 0.8) + 
    scale_x_logicle() +
    facet_wrap(~date + replicate, 
               labeller = labeller(.multi_line = FALSE)) + 
    ylab("H2O2 concentration")
  print(p)
Picking joint bandwidth of 0.0713
Picking joint bandwidth of 0.0707
Picking joint bandwidth of 0.0878
Picking joint bandwidth of 0.0624
Picking joint bandwidth of 0.08
Picking joint bandwidth of 0.0904

#}

BL3.H (red staining)

#for(date in c("011124", "011524", "011624")){
  p <- ggcyto(gs, aes(x = BL3.H), subset = "singlet") + 
    geom_density_ridges(aes(y = factor(treatment, levels = tr.levels)), 
                            fill = "forestgreen", alpha = 0.8) + 
    scale_x_logicle() +
    facet_wrap(~date + replicate, 
               labeller = labeller(.multi_line = FALSE)) + 
    ylab("H2O2 concentration")
  print(p)
Picking joint bandwidth of 0.0718
Picking joint bandwidth of 0.0703
Picking joint bandwidth of 0.0747
Picking joint bandwidth of 0.0678
Picking joint bandwidth of 0.0595
Picking joint bandwidth of 0.0618

#}

Plotting initial phenotype

Here, we plot the G+R staining patterns from multiple days to observe the consistency of the assay

p <- ggcyto(gs[pData(gs)$replicate == "A" & 
                 pData(gs)$treatment %in% c("0", "10", "100", "1000") &
                 pData(gs)$date != "2023-09-18"],
            aes(x = BL1.H, y = BL3.H), subset = "singlet") + 
  geom_hex(aes(fill = after_stat(density)), bins = 64) + 
  facet_grid(date ~ factor(treatment, levels = tr.levels),
             labeller = labeller(.multi_line = F)) +
  scale_x_logicle(breaks = c(10^2, 10^3, 10^4)) + 
  scale_y_logicle(breaks = c(10^2, 10^3, 10^4)) + 
  theme_minimal(base_size = 16) + 
  panel_border(color = "gray20") + #background_grid(major = "none", minor = "none") +
  theme(
    #axis.line = element_blank(),
    strip.text.y = element_blank(),
    strip.text.x = element_text(size = rel(1.2), color = "steelblue", face = 2),
    axis.text = element_text(size = rel(0.6)),
    plot.title = element_blank(),
    legend.position = "none",
    axis.title = element_blank()
  )

p
ggsave("../output/fig1-staining-consistency-20240911.png", width = 5, height = 4)

LS0tCnRpdGxlOiAiSWxsdXN0cmF0ZSB0aGUgaW5pdGlhbCBwaGVub3R5cGVzIgphdXRob3I6IEJpbiBIZSwgSGFueGkgVGFuZwpkYXRlOiAiMjAyNC0wOS0wNSAodXBkYXRlZCBgciBTeXMudGltZSgpYCkiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDQKICAgIGNvZGVfZm9sZGluZzogaGlkZQotLS0KCiMgQmFja2dyb3VuZApUaGlzIGZvbGRlciBjb250YWlucyBhbmFseXNlcyBmb3Igc2hvd2luZyB0aGUgaW5pdGlhbCBzdGFpbmluZyBwYXR0ZXJucyB3ZSBvYnNlcnZlZCB3aGVuIGFwcGx5aW5nIEZ1bmdhTGlnaHQgdG8gb3hpZGF0aXZlIHN0cmVzcyBkYW1hZ2VkIF9DLiBnbGFicmF0YV8gY2VsbHMuIE5vdGUgdGhhdCB0aGVzZSBhcmUgbm90IGV4YWN0bHkgb3VyIGZpcnN0IHRyaWFsIHJlc3VsdHMsIHdoaWNoIHN1ZmZlciBhIGxvdCBtb3JlIGluY29uc2lzdGVuY2llcyBhbmQgYWJub3JtYWxpdGllcywgZHVlIHRvIG91ciBpbmV4cGVyaWVuY2Ugd2l0aCB0aGUgcmVhZ2VudCBhbmQgcHJvdG9jb2wgaW4gZ2VuZXJhbC4gUmF0aGVyLCB0aGVzZSBhcmUgdGhlICJhbHBoYSIgdGVzdHMgb2YgdGhlIHByb3RvY29sIGFmdGVyIHNvbWUgcHJlbGltaW5hcnkgdGVzdHMsIGFuZCByZXByZXNlbnQgYXQgbGVhc3QgInNlbnNpYmxlIiByZXN1bHRzLCBhbHRob3VnaCB3aXRoIGltcG9ydGFudCBjYXZlYXRzIHRoYXQgd2UgYWRkcmVzc2VkIGluIHRoZSBsYXRlciBwcm90b2NvbCBvcHRpbWl6YXRpb24gc3RlcHMuCgoKYGBge3Igc2V0dXAsIG1lc3NhZ2U9RkFMU0V9CnJlcXVpcmUodGlkeXZlcnNlKQpyZXF1aXJlKGZsb3dDb3JlKQpyZXF1aXJlKGZsb3dDbHVzdCkKcmVxdWlyZShvcGVuQ3l0bykKcmVxdWlyZShnZ2N5dG8pCnJlcXVpcmUoY293cGxvdCkKcmVxdWlyZShnZ3JpZGdlcykKYGBgCgpgYGB7cn0Kb2xkIDwtIHRoZW1lX3NldCh0aGVtZV9taW5pbWFsKCkpCmBgYAoKIyBJbXBvcnQgZGF0YQoKPiBGQ1MgZmlsZXMgYXJlIHN0b3JlZCBpbiBSRFNTL3VzZXIvZmxvdyBjeXRvbWV0cnksIEZDUyBpcyByZWFkIGFuZCB3cml0ZSBpbnRvIGFuIGlucHV0IHRzdiB0YWJsZS4gVGhlIHRzdiBmaWxlIGlzIGF2YWxpYWJsZSBmcm9tIHRoZSBJbnB1dCBmb2xkZXIuCgpgYGB7cn0KIyB1c2UgcmVsYXRpdmUgcGF0aCB0byBtYWtlIGl0IGVhc2llciBmb3IgY29sbGFib3JhdGlvbgpkYXRhLnBhdGggPSAiL1ZvbHVtZXMvcmRzc19iaGUyL1VzZXIvSGFueGktVGFuZy9mbG93X2N5dG9tZXRyeS8yMDIzMDkyOSBGdW5nYUxpZ2h0LUNnbGEtYW5hbHlzaXMvIgpkYXQwIDwtIHJlYWQuZmxvd1NldChwYXRoID0gZGF0YS5wYXRoLCB0cmFuc2Zvcm1hdGlvbiA9IEZBTFNFLCAgIyB0aGUgb3JpZ2luYWwgdmFsdWVzIGFyZSBhbHJlYWR5IGxpbmVhcml6ZWQuIAogICAgICAgICAgICAgICAgICAgICBlbXB0eVZhbHVlID0gRkFMU0UsICBhbHRlci5uYW1lcyA9IFRSVUUsICAgIyBjaGFuZ2UgcGFyYW1ldGVyIG5hbWVzIHRvIFIgZm9ybWF0CiAgICAgICAgICAgICAgICAgICAgIGNvbHVtbi5wYXR0ZXJuID0gIi5IfEZTQ3xTU0MiKSAjIG9ubHkgbG9hZCB0aGUgaGVpZ2h0IHZhcmlhYmxlcyBmb3IgdGhlIGZsdW9yZXNjZW50IHBhcmFtZXRlcnMKYGBgCgojIyBTaW1wbGlmeSB0aGUgc2FtcGxlIG5hbWVzCgpgYGB7cn0KI3NvdXJjZSgiLi4vLi4vLi4vMDAtU2hhcmVkLzAxLXNjcmlwdC8yMDIyMDMyNi1zaW1wbGlmeS1uYW1lcy1zdWJyb3V0aW5lLlIiKQpvcmlOYW1lcyA8LSBzYW1wbGVOYW1lcyhkYXQwKQp0bXAgPC0gc3RyX3NwbGl0KG9yaU5hbWVzLCBwYXR0ZXJuID0gIl8iLCBzaW1wbGlmeSA9IFRSVUUpWyxjKDEsIDUpXQpjb2xuYW1lcyh0bXApIDwtIGMoIkRhdGUiLCAiVHJlYXRtZW50IikKc2FtcGxlIDwtIGRhdGEuZnJhbWUodG1wKSAlPiUgCiAgbXV0YXRlKAogICAgZGF0ZSA9IG1keShEYXRlKSwKICAgIHJlcGxpY2F0ZSA9IGlmZWxzZShzdHJfc3ViKFRyZWF0bWVudCwgMSwgMSkgPT0gIkIiLCAiQiIsICJBIiksCiAgICB0cmVhdG1lbnQgPSBzdWIoIkIgIiwgIiIsIFRyZWF0bWVudCkgJT4lIHN1YigiLmZjcyIsICIiLCAuKSAlPiUgCiAgICAgIGdzdWIoIjFNIiwgIjEwMDAiLCAuKSAlPiUgZ3N1YigiTW9jayIsICIwIiwgLiksCiAgICB0cmVhdG1lbnQgPSBmYWN0b3IodHJlYXRtZW50LCBsZXZlbHMgPSBzb3J0KGFzLm51bWVyaWModW5pcXVlKHRyZWF0bWVudCkpKSkKICApICU+JSAKICBzZWxlY3QoLURhdGUsIC0gVHJlYXRtZW50KQp0ci5sZXZlbHMgPC0gbGV2ZWxzKHNhbXBsZSR0cmVhdG1lbnQpCnJvd25hbWVzKHNhbXBsZSkgPC0gb3JpTmFtZXMKZGF0IDwtIGRhdDAgIyBtYWtlIGEgY29weQpwRGF0YShkYXQpIDwtIHNhbXBsZQpwcmludChwRGF0YShkYXQpICU+JSBhc190aWJibGUoKSkKd3JpdGVfdHN2KHBEYXRhKGRhdCksIGZpbGUgPSAiLi4vaW5wdXQvMjAyMzA5Mjktc2FtcGxlLWxpc3QudHN2IikKYGBgCgojIEJhc2ljIGdhdGluZwojIyBPdXRsaWVyClRoZSBmb2xsb3dpbmcgZ2FwaGluZyBzdGVwcyBhcmUgdXNlZCB0byBnYXRlIHNpbmdsZXRzIGJ5IEZTQyBhbmQgU1NDIHZhbHVlcy4gT25seSBzaW5nbGV0cyBhcmUgaW5jbHVkZWQgaW4gYW5hbHlzaXMuCgpgYGB7cn0Kb3V0bGllci5nYXRlIDwtIHJlY3RhbmdsZUdhdGUoZmlsdGVySWQgPSAiLW91dGxpZXIiLCAiRlNDLkgiID0gYygxLjJlNSwgMWU2KSwgIlNTQy5IIiA9IGMoMWUyLCAxZTYpKQpnZ2N5dG8oZGF0W2MoMiwyMCldLCBhZXMoeCA9IEZTQy5ILCB5ID0gU1NDLkgpLCBzdWJzZXQgPSAicm9vdCIpICsKICBnZW9tX2hleChiaW5zID0gNjQpICsgZ2VvbV9nYXRlKG91dGxpZXIuZ2F0ZSkgKyBmYWNldF93cmFwKH5uYW1lLCBuY29sID0gMikgKyBnZ2N5dG9fcGFyX3NldChsaW1pdHMgPSAiaW5zdHJ1bWVudCIpCiMgLS0tLQojIHVuY29tbWVudCB0aGUgY29kZSBiZWxvdyB0byBjaGVjayBvbiBhbGwgZGF0YQojIC0tLS0KIyBnZ2N5dG8oZGF0LCBhZXMoeCA9IEZTQy5ILCB5ID0gU1NDLkgpLCBzdWJzZXQgPSAicm9vdCIpICsKIyAgIGdlb21faGV4KGJpbnMgPSA2NCkgKyBnZW9tX2dhdGUob3V0bGllci5nYXRlKSArIGZhY2V0X3dyYXAofm5hbWUsIG5jb2wgPSA5KSArIGdnY3l0b19wYXJfc2V0KGxpbWl0cyA9ICJpbnN0cnVtZW50IikgKwojICAgdGhlbWVfbWluaW1hbF9ncmlkKCkKIyAtLS0tCiMgZW5kCiMgLS0tLQpgYGAKQWRkIGdhdGUgdG8gR1MKYGBge3J9CiMgc2hvcnRlbiB0aGUgbmFtZXMgb2YgdGhlIHNhbXBsZXMgZm9yIHBsb3R0aW5nCnNob3J0TmFtZXMgPC0gd2l0aChwRGF0YShkYXQpLCAKICAgICAgICAgICAgICAgICAgIHBhc3RlKHN1YnN0cihkYXRlLCA2LCAxMCksIHJlcGxpY2F0ZSwKICAgICAgICAgICAgICAgICAgICAgICAgIHBhc3RlMCh0cmVhdG1lbnQsICJtTSIpLCBzZXAgPSAiXyIpKQpuYW1lcyhzaG9ydE5hbWVzKSA8LSBzYW1wbGVOYW1lcyhkYXQpCmdzIDwtIEdhdGluZ1NldChkYXQpICMgY3JlYXRlIGEgR2F0aW5nU2V0CiMgcmVuYW1lIHRoZSBHYXRpbmdTZXQKaWYoYWxsKHNhbXBsZU5hbWVzKGdzKSA9PSBuYW1lcyhzaG9ydE5hbWVzKSkpCiAgcERhdGEoZ3MpJG5hbWUgPC0gc2hvcnROYW1lcwojIGFkZCB0aGUgb3V0bGllciBnYXRlCmdzX3BvcF9hZGQoZ3MsIG91dGxpZXIuZ2F0ZSwgcGFyZW50ID0gInJvb3QiKQojIGNvbXB1dGUKcmVjb21wdXRlKGdzKQpgYGAKCiMjIEdhdGUgZm9yIHNpbmdsZXRzCgpgYGB7ciBmaWcud2lkdGg9NCwgZmlnLmhlaWdodD00fQpzY1BhcnMgPC0gZ2djeXRvX3Bhcl9zZXQobGltaXRzID0gbGlzdCh4ID0gYygwLDFlNiksIHkgPSBjKDMwLDMwMCkpKQpleCA8LSBTdWJzZXQoZGF0W1sxOV1dLCBvdXRsaWVyLmdhdGUpCnBvbHlnb24gPC0gbWF0cml4KGMoMWU1LCAxZTUsIDFlNiwgMWU2LCAKICAgICAgICAgICAgICAgICAgICA2MCwgNzUsIDEzNSw2MCksIG5jb2wgPSAyKQpjb2xuYW1lcyhwb2x5Z29uKSA8LSBjKCJGU0MuSCIsICJGU0MuVyIpCnNpbmdsZXQuZ2F0ZSA8LSBwb2x5Z29uR2F0ZShmaWx0ZXJJZCA9ICJzaW5nbGV0IiwgLmdhdGUgPSBwb2x5Z29uKQpnZ2N5dG8oZXgsIGFlcyh4ID0gRlNDLkgsIHkgPSBGU0MuVykpICsgZ2VvbV9oZXgoYmlucyA9IDEyOCkgKyBnZW9tX2dhdGUoc2luZ2xldC5nYXRlKSArIGdlb21fc3RhdHMoKSArIHNjUGFycwpgYGAKCgpBZGQgdGhpcyBnYXRlIHRvIHRoZSBnYXRpbmdTZXQKYGBge3J9CmdzX3BvcF9hZGQoZ3MsIHNpbmdsZXQuZ2F0ZSwgcGFyZW50ID0gIi1vdXRsaWVyIiwgbmFtZSA9ICJzaW5nbGV0IikKcmVjb21wdXRlKGdzKQpgYGAKYGBge3IgZmlnLndpZHRoPTZ9CnNjUGFycyA8LSBnZ2N5dG9fcGFyX3NldChsaW1pdHMgPSBsaXN0KHggPSBjKDAsMWU2KSwgeSA9IGMoMzAsMjAwKSkpCnRlc3QgPC0gc2FtcGxlKDE6bGVuZ3RoKGdzKSwgOCkKZ2djeXRvKGdzW3Rlc3RdLCBhZXMoeCA9IEZTQy5ILCB5ID0gRlNDLlcpLCBzdWJzZXQgPSAiLW91dGxpZXIiKSArCiAgZ2VvbV9oZXgoYmlucyA9IDEyOCkgKyBnZW9tX2dhdGUoInNpbmdsZXQiKSArIGZhY2V0X3dyYXAofm5hbWUsIG5jb2wgPSA0KSArIAogIHNjUGFycyMgKyB0aGVtZShzdHJpcC50ZXh0ID0gZWxlbWVudF9ibGFuaygpKQoKYGBgCkNoZWNrIG51bWJlciBvZiBldmVudHMgYWZ0ZXIgZ2F0aW5nCmBgYHtyfQpnYXRlZF9ldmVudHMgPC0gZ3NfcG9wX2dldF9zdGF0cyhncywgInNpbmdsZXQiKSAlPiUgCiAgbGVmdF9qb2luKHBEYXRhKGdzKSAlPiUgcm93bmFtZXNfdG9fY29sdW1uKHZhciA9ICJzYW1wbGUiKSwgYnkgPSAic2FtcGxlIikgJT4lIAogIGFycmFuZ2UoY291bnQpCgpnYXRlZF9ldmVudHMgJT4lIAogIG11dGF0ZShuYW1lID0gZmN0X3Jlb3JkZXIobmFtZSwgY291bnQpKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gbmFtZSwgeSA9IGNvdW50KSkgKwogIGdlb21fY29sKCkgKwogIHRoZW1lX2Nvd3Bsb3QoKSArIHhsYWIoTlVMTCkgKwogIHRoZW1lKAogICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgc2l6ZSA9IHJlbCgwLjUpKQogICkKYGBgCgojIyBGU0MgYW5kIFNTQyB2cyB0cmVhdG1lbnQgYW5kIGR5ZSB7LnRhYnNldH0KCiMjIyBGU0MKCmBgYHtyfQptdWx0X2Zvcm1hdCA8LSBmdW5jdGlvbigpIHsKICAgICBmdW5jdGlvbih4KSBmb3JtYXQoeC8xMDAwMCxkaWdpdHMgPSAyKSAKfQojZm9yKGRhdGUgaW4gdW5pcXVlKHNhbXBsZSRkYXRlKSl7CiAgcCA8LSBnZ2N5dG8oZ3MsIGFlcyh4ID0gRlNDLkgpLCBzdWJzZXQgPSAic2luZ2xldCIpICsgCiAgICBnZW9tX2RlbnNpdHlfcmlkZ2VzKGFlcyh5ID0gZmFjdG9yKHRyZWF0bWVudCwgbGV2ZWxzID0gdHIubGV2ZWxzKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJmb3Jlc3RncmVlbiIsIGFscGhhID0gMC44KSArIAogICAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IG11bHRfZm9ybWF0KCksIG5hbWUgPSAiRlNDLkggeCAxMDAwMCIpICsKICAgIGZhY2V0X3dyYXAofmRhdGUgKyByZXBsaWNhdGUsIAogICAgICAgICAgICAgICBsYWJlbGxlciA9IGxhYmVsbGVyKC5tdWx0aV9saW5lID0gRkFMU0UpKSArIAogICAgeWxhYigiSDJPMiBjb25jZW50cmF0aW9uIikKICBwcmludChwKQojfQpgYGAKCj4gdGhlcmUgaXMgYSB0cmVuZCBvZiBkZWNyZWFzaW5nIEZTQyB3aXRoIHN0cm9uZ2VyIEgyTzIgdHJlYXRtZW50CgojIyMgU1NDCgpgYGB7cn0KICBwIDwtIGdnY3l0byhncywgYWVzKHggPSBTU0MuSCksIHN1YnNldCA9ICJzaW5nbGV0IikgKyAKICAgIGdlb21fZGVuc2l0eV9yaWRnZXMoYWVzKHkgPSBmYWN0b3IodHJlYXRtZW50LCBsZXZlbHMgPSB0ci5sZXZlbHMpKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gImZvcmVzdGdyZWVuIiwgYWxwaGEgPSAwLjgpICsgCiAgICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0gbXVsdF9mb3JtYXQoKSwgbmFtZSA9ICJTU0MuSCB4IDEwMDAwIikgKwogICAgZmFjZXRfd3JhcCh+ZGF0ZSArIHJlcGxpY2F0ZSwgCiAgICAgICAgICAgICAgIGxhYmVsbGVyID0gbGFiZWxsZXIoLm11bHRpX2xpbmUgPSBGQUxTRSkpICsgCiAgICB5bGFiKCJIMk8yIGNvbmNlbnRyYXRpb24iKQogIHByaW50KHApCgpgYGAKPiBTU0MgKGNvbXBsZXhpdHkgb2YgY2VsbCwgcm91Z2hseSkgZGVjcmVhc2VzIHdpdGggaW5jcmVhc2luZyBIMk8yIGNvbmNlbnRyYXRpb24KCiMjIyBCTDEuSCAoZ3JlZW4gc3RhaW5pbmcpCmBgYHtyfQojZm9yKGRhdGUgaW4gYygiMDExMTI0IiwgIjAxMTUyNCIsICIwMTE2MjQiKSl7CiAgcCA8LSBnZ2N5dG8oZ3MsIGFlcyh4ID0gQkwxLkgpLCBzdWJzZXQgPSAic2luZ2xldCIpICsgCiAgICBnZW9tX2RlbnNpdHlfcmlkZ2VzKGFlcyh5ID0gZmFjdG9yKHRyZWF0bWVudCwgbGV2ZWxzID0gdHIubGV2ZWxzKSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsbCA9ICJmb3Jlc3RncmVlbiIsIGFscGhhID0gMC44KSArIAogICAgc2NhbGVfeF9sb2dpY2xlKCkgKwogICAgZmFjZXRfd3JhcCh+ZGF0ZSArIHJlcGxpY2F0ZSwgCiAgICAgICAgICAgICAgIGxhYmVsbGVyID0gbGFiZWxsZXIoLm11bHRpX2xpbmUgPSBGQUxTRSkpICsgCiAgICB5bGFiKCJIMk8yIGNvbmNlbnRyYXRpb24iKQogIHByaW50KHApCiN9CmBgYAoKCiMjIyBCTDMuSCAocmVkIHN0YWluaW5nKQpgYGB7cn0KI2ZvcihkYXRlIGluIGMoIjAxMTEyNCIsICIwMTE1MjQiLCAiMDExNjI0IikpewogIHAgPC0gZ2djeXRvKGdzLCBhZXMoeCA9IEJMMy5IKSwgc3Vic2V0ID0gInNpbmdsZXQiKSArIAogICAgZ2VvbV9kZW5zaXR5X3JpZGdlcyhhZXMoeSA9IGZhY3Rvcih0cmVhdG1lbnQsIGxldmVscyA9IHRyLmxldmVscykpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGwgPSAiZm9yZXN0Z3JlZW4iLCBhbHBoYSA9IDAuOCkgKyAKICAgIHNjYWxlX3hfbG9naWNsZSgpICsKICAgIGZhY2V0X3dyYXAofmRhdGUgKyByZXBsaWNhdGUsIAogICAgICAgICAgICAgICBsYWJlbGxlciA9IGxhYmVsbGVyKC5tdWx0aV9saW5lID0gRkFMU0UpKSArIAogICAgeWxhYigiSDJPMiBjb25jZW50cmF0aW9uIikKICBwcmludChwKQojfQpgYGAKCiMgUGxvdHRpbmcgaW5pdGlhbCBwaGVub3R5cGUKSGVyZSwgd2UgcGxvdCB0aGUgRytSIHN0YWluaW5nIHBhdHRlcm5zIGZyb20gbXVsdGlwbGUgZGF5cyB0byBvYnNlcnZlIHRoZSBjb25zaXN0ZW5jeSBvZiB0aGUgYXNzYXkKYGBge3J9CnAgPC0gZ2djeXRvKGdzW3BEYXRhKGdzKSRyZXBsaWNhdGUgPT0gIkEiICYgCiAgICAgICAgICAgICAgICAgcERhdGEoZ3MpJHRyZWF0bWVudCAlaW4lIGMoIjAiLCAiMTAiLCAiMTAwIiwgIjEwMDAiKSAmCiAgICAgICAgICAgICAgICAgcERhdGEoZ3MpJGRhdGUgIT0gIjIwMjMtMDktMTgiXSwKICAgICAgICAgICAgYWVzKHggPSBCTDEuSCwgeSA9IEJMMy5IKSwgc3Vic2V0ID0gInNpbmdsZXQiKSArIAogIGdlb21faGV4KGFlcyhmaWxsID0gYWZ0ZXJfc3RhdChkZW5zaXR5KSksIGJpbnMgPSA2NCkgKyAKICBmYWNldF9ncmlkKGRhdGUgfiBmYWN0b3IodHJlYXRtZW50LCBsZXZlbHMgPSB0ci5sZXZlbHMpLAogICAgICAgICAgICAgbGFiZWxsZXIgPSBsYWJlbGxlcigubXVsdGlfbGluZSA9IEYpKSArCiAgc2NhbGVfeF9sb2dpY2xlKGJyZWFrcyA9IGMoMTBeMiwgMTBeMywgMTBeNCkpICsgCiAgc2NhbGVfeV9sb2dpY2xlKGJyZWFrcyA9IGMoMTBeMiwgMTBeMywgMTBeNCkpICsgCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNikgKyAKICBwYW5lbF9ib3JkZXIoY29sb3IgPSAiZ3JheTIwIikgKyAjYmFja2dyb3VuZF9ncmlkKG1ham9yID0gIm5vbmUiLCBtaW5vciA9ICJub25lIikgKwogIHRoZW1lKAogICAgI2F4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHN0cmlwLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDEuMiksIGNvbG9yID0gInN0ZWVsYmx1ZSIsIGZhY2UgPSAyKSwKICAgIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gcmVsKDAuNikpLAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkKICApCgpwCmdnc2F2ZSgiLi4vb3V0cHV0L2ZpZzEtc3RhaW5pbmctY29uc2lzdGVuY3ktMjAyNDA5MTEucG5nIiwgd2lkdGggPSA1LCBoZWlnaHQgPSA0KQpgYGAKCg==